#include "PassWordsPromise.h"



LittleBasically::_RuleParameter::_RuleParameter()
{
	nLength = 0;
	nUpper = 0;
	nLower = 0;
	nDigit = 0;
	nSymbol = 0;
	nMidDigitSymbol = 0;
	nRequirement = 0;
	for (int i = 0; i < 256; ++i){
		RepeatChar[0] = 0;
	}
	nConsecUpper = 0;
	nConsecLower = 0;
	nConsecDigit = 0;
	nSequence = 0;
}



LittleBasically::_RuleParameter::~_RuleParameter()
{

}



void LittleBasically::_RuleParameter::InitRuleParameter()
{
	nLength = 0;
	nUpper = 0;
	nLower = 0;
	nDigit = 0;
	nSymbol = 0;
	nMidDigitSymbol = 0;
	nRequirement = 0;
	for (int i = 0; i < 256; ++i){
		RepeatChar[0] = 0;
	}
	nConsecUpper = 0;
	nConsecLower = 0;
	nConsecDigit = 0;
	nSequence = 0;
}



int LittleBasically::CheckPsdStrength::GetPasswordLevel(int PassWordScore)
{
	int results = 0;
	if(PassWordScore < 20) {
		results = 1;
	}
	else if(PassWordScore < 40) {
		results = 2;
	}
	else if(PassWordScore < 60) {
		results = 3;
	}
	else if(PassWordScore < 80) {
		results = 4;
	}
	else{
		results = 5;
	}
	return results;
}



int LittleBasically::CheckPsdStrength::GetPasswordScore(const std::string strPassWord)
{
	RuleParameter.InitRuleParameter();
	BeginProcess(strPassWord);

	return countScore();
}



void LittleBasically::CheckPsdStrength::BeginProcess(const std::string strPassWord)
{
	char * PassWord = (char*)strPassWord.data();
	if( nullptr == PassWord ){
		return;
	}
	char *pass_nospace = (char *)malloc(strlen(PassWord)+1);
	char *pass_nospace_lower = (char *)malloc(strlen(PassWord)+1);
	if( nullptr == pass_nospace || nullptr == pass_nospace_lower ){
		return;
	}
	//
	int j = 0;
	for( int i=0; '\0'!= PassWord[i]; ++i){
		if(!isspace(PassWord[i])){
			pass_nospace[j]=PassWord[i];
			pass_nospace_lower[j]=tolower(PassWord[i]);
			++j;
		}
	}
	pass_nospace[j] = '\0';
	RuleParameter.nLength = strlen(pass_nospace);
	countRepeat(pass_nospace_lower);
	countNumbers(pass_nospace);
	countSeqNumbers(pass_nospace);
	//
	free(pass_nospace);
	free(pass_nospace_lower);
}



void LittleBasically::CheckPsdStrength::countRepeat(const char *password)
{
	if( nullptr == password ){
		return;
	}
	//
	for (int i = 0; i < RuleParameter.nLength; ++i){
		++RuleParameter.RepeatChar[password[i]];
	}
}



void LittleBasically::CheckPsdStrength::countNumbers(const char *password)
{
	if( nullptr == password ){
		return;
	}
	//
	int last_upper_pos = -1;
	int last_lower_pos = -1;
	int last_digit_pos = -1;
	for (int i = 0; i < RuleParameter.nLength; ++i){
		if(isupper(password[i])){
			if(last_upper_pos != -1 && last_upper_pos+1 == i) {
				++RuleParameter.nConsecUpper;
			}
			last_upper_pos = i;
			++RuleParameter.nUpper;
		}
		else if(islower(password[i])){
			if(last_lower_pos != -1 && last_lower_pos+1 == i) {
				++RuleParameter.nConsecLower;
			}
			last_lower_pos = i;
			++RuleParameter.nLower;
		}
		else if(isdigit(password[i])){
			if(last_digit_pos != -1 && last_digit_pos+1 == i) {
				++RuleParameter.nConsecDigit;
			}
			if(i > 0 && i < RuleParameter.nLength - 1) {
				++RuleParameter.nMidDigitSymbol;
			}
			last_digit_pos = i;
			++RuleParameter.nDigit;
		}
		else{
			if(i > 0 && i < RuleParameter.nLength - 1) {
				++RuleParameter.nMidDigitSymbol;
			}
			++RuleParameter.nSymbol;
		}
	}

	if(RuleParameter.nLower>0){
		++RuleParameter.nRequirement;
	}
	if(RuleParameter.nUpper>0){
		++RuleParameter.nRequirement;
	}
	if(RuleParameter.nDigit>0){
		++RuleParameter.nRequirement;
	}
	if(RuleParameter.nSymbol>0){
		++RuleParameter.nRequirement;
	}
}



void LittleBasically::CheckPsdStrength::countSeqNumbers(const char *password)
{
	if( nullptr == password ){
		return;
	}
	else if(RuleParameter.nLength < 3){
		return;
	}
	//
	int inc_count = 1;
	int dec_count = 1;
	//
	for(int i = 1; i < RuleParameter.nLength; ++i ){
		if(isalnum(password[i]) && isalnum(password[i-1])) {
			if(password[i] - password[i-1] == 1){
				if(dec_count < 3) ++inc_count;
				dec_count = 1;
			}
			else if(password[i] - password[i-1] == -1){
				if(inc_count < 3) ++dec_count;
				inc_count = 1;
			}
			else{
				inc_count = dec_count = 1;
			}
		}
		else{
			inc_count = dec_count = 1;
		}

		if(inc_count >= 3 || dec_count >= 3){
			++RuleParameter.nSequence;
		}
	}
}



int LittleBasically::CheckPsdStrength::countScore()
{
	int score = 0;
	if (0 !=  RuleParameter.nLength ){
		score += RuleParameter.nLength * 4;
		if (0 !=  RuleParameter.nUpper){
			score += (RuleParameter.nLength - RuleParameter.nUpper) * 2;
		}
		if (0 !=  RuleParameter.nLower){
			score += (RuleParameter.nLength - RuleParameter.nLower) * 2;
		}
		if (RuleParameter.nLength !=  RuleParameter.nDigit){
			score += RuleParameter.nDigit * 4;
		}

		score += RuleParameter.nSymbol * 6;
		score += RuleParameter.nMidDigitSymbol * 2;

		if (RuleParameter.nLength >= 8 && RuleParameter.nRequirement >= 3){
			score += (RuleParameter.nRequirement + 1) * 2;
		}
		if (RuleParameter.nDigit == RuleParameter.nLength || RuleParameter.nLower + RuleParameter.nUpper == RuleParameter.nLength){
			score -= RuleParameter.nLength;
		}
		for(int i = 0, n = 0; i < 256; ++i) {
			n = RuleParameter.RepeatChar[i];
			if(n > 1) {
				score -= n * ( n - 1 );
			}
		}
		score -= RuleParameter.nConsecDigit * 2;
		score -= RuleParameter.nConsecLower * 2;
		score -= RuleParameter.nConsecUpper * 2;
		score -= RuleParameter.nSequence * 3;
		//
		score = (score < 0) ? 0 :((score >100) ? 100 : score);
	}
	return score;
}



